﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using RuoVea.DynamicWebApi;
using RuoVea.ExDto;
using RuoVea.ExEnum;
using RuoVea.ExIdGen;
using RuoVea.ExLog;
using RuoVea.OmiApi.Upload.Language;
using RuoVea.OmiApi.Upload.Service.Dto;

namespace RuoVea.OmiApi.Upload.Service;

/// <summary>
/// 文件上传管理服务 🔷
/// 提供单文件和多文件上传功能，支持按文件类型分类和验证
/// </summary>
[ApiExplorerSettings(GroupName = "Upload")]
public class FileUploadService : IApplicationService
{
    private readonly IWebHostEnvironment _environment;
    private readonly UploadConfig _uploadConfig;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="environment">Web主机环境，用于获取应用程序根路径等环境信息</param>
    /// <param name="uploadConfig">文件上传配置选项</param> 
    public FileUploadService(IWebHostEnvironment environment, IOptions<UploadConfig> uploadConfig)
    {
        _environment = environment;
        _uploadConfig = uploadConfig.Value;
    }

    #region 分类上传路由

    ///// <summary>
    ///// 通用文件上传（支持所有类型）
    ///// </summary>
    ///// <param name="file">要上传的文件</param>
    ///// <returns>上传结果，包含成功状态和文件信息</returns>
    //[HttpPost("upload")]
    //[DisableRequestSizeLimit]
    //public async Task<RestfulResult> upload(IFormFile file)
    //{
    //    return await UploadFileInternal(file, "general");
    //}

    /// <summary>
    /// 图片文件上传
    /// </summary>
    /// <param name="file">要上传的图片文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Image(IFormFile file)
    {
        return await UploadFileByCategory(file, "Images", "image");
    }

    /// <summary>
    /// 文档文件上传
    /// </summary>
    /// <param name="file">要上传的文档文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Document(IFormFile file)
    {
        return await UploadFileByCategory(file, "Documents", "document");
    }

    /// <summary>
    /// 电子表格文件上传
    /// </summary>
    /// <param name="file">要上传的电子表格文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Spreadsheet(IFormFile file)
    {
        return await UploadFileByCategory(file, "Spreadsheets", "spreadsheet");
    }

    /// <summary>
    /// 演示文稿文件上传
    /// </summary>
    /// <param name="file">要上传的演示文稿文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Presentation(IFormFile file)
    {
        return await UploadFileByCategory(file, "Presentations", "presentation");
    }

    /// <summary>
    /// 压缩文件上传
    /// </summary>
    /// <param name="file">要上传的压缩文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Archive(IFormFile file)
    {
        return await UploadFileByCategory(file, "Archives", "archive");
    }

    /// <summary>
    /// 代码文件上传
    /// </summary>
    /// <param name="file">要上传的代码文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Code(IFormFile file)
    {
        return await UploadFileByCategory(file, "Code", "code");
    }

    /// <summary>
    /// 视频文件上传
    /// </summary>
    /// <param name="file">要上传的视频文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Video(IFormFile file)
    {
        return await UploadFileByCategory(file, "Videos", "video");
    }

    /// <summary>
    /// 音频文件上传
    /// </summary>
    /// <param name="file">要上传的音频文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Audio(IFormFile file)
    {
        return await UploadFileByCategory(file, "Audios", "audio");
    }

    /// <summary>
    /// 电子书文件上传
    /// </summary>
    /// <param name="file">要上传的电子书文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Ebook(IFormFile file)
    {
        return await UploadFileByCategory(file, "Ebooks", "ebook");
    }

    /// <summary>
    /// 其他文件上传
    /// </summary>
    /// <param name="file">要上传的其他类型文件</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> Other(IFormFile file)
    {
        return await UploadFileByCategory(file, "Others", "other");
    }

    /// <summary>
    /// 多文件上传（支持所有类型）
    /// </summary>
    /// <param name="files">要上传的文件列表</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> MultipleFiles(List<IFormFile> files)
    {
        return await UploadMultipleFilesInternal(files, "general");
    }

    /// <summary>
    /// 按分类多文件上传
    /// </summary>
    /// <param name="files">要上传的文件列表</param>
    /// <param name="category">文件分类</param>
    /// <returns>上传结果</returns>
    [HttpPost]
    [DisableRequestSizeLimit]
    public async Task<RestfulResult> MultipleFilesByCategory(List<IFormFile> files, string category)
    {
        return await UploadMultipleFilesInternal(files, category.ToLower());
    }

    #endregion

    #region 内部方法

    ///// <summary>
    ///// 内部文件上传方法
    ///// </summary>
    //[NonAction]
    //private async Task<RestfulResult> UploadFileInternal(IFormFile file, string routeCategory)
    //{
    //    RestfulResult restfulResult = new() { Code = CodeStatus.BadRequest };
    //    if (file == null || file.Length == 0)
    //    {
    //        restfulResult.Message = i18n.Prompt_SelectFile;
    //        return restfulResult;
    //    }
    //    if (!ValidateFile(file, out var errorMessage))
    //    {
    //        restfulResult.Message = errorMessage;
    //        return restfulResult;
    //    }
    //    try
    //    {
    //        var result = await UploadFileAsync(file, routeCategory);
    //        restfulResult.Code = CodeStatus.OK;
    //        restfulResult.Message = i18n.Message_UploadSuccess;
    //        restfulResult.Data = result;
    //    }
    //    catch (Exception ex)
    //    {
    //         LogFactory.Error($"文件上传失败: { file.FileName}",ex);
    //        restfulResult.Message = i18n.Error_UploadFailed;
    //    }
    //    return restfulResult;
    //}

    /// <summary>
    /// 按分类上传文件
    /// </summary>
    [NonAction]
    private async Task<RestfulResult> UploadFileByCategory(IFormFile file, string expectedCategory, string routeCategory)
    {
        RestfulResult restfulResult = new() { Code = CodeStatus.BadRequest };
        if (file == null || file.Length == 0)
        {
            restfulResult.Message = i18n.Prompt_SelectFile;
            return restfulResult;
        }

        // 验证文件是否属于指定分类
        var actualCategory = GetFileCategory(file);
        if (actualCategory != expectedCategory && actualCategory != "Others")
        {
            restfulResult.Message = string.Format(i18n.Error_FileCategoryMismatch, expectedCategory, actualCategory);
            return restfulResult;
        }

        if (!ValidateFile(file, out var errorMessage))
        {
            restfulResult.Message = errorMessage;
            return restfulResult;
        }

        try
        {
            var result = await UploadFileAsync(file, routeCategory);
            restfulResult.Code = CodeStatus.OK;
            restfulResult.Message = i18n.Message_UploadSuccess;
            restfulResult.Data = result;
        }
        catch (Exception ex)
        {
            LogFactory.Error($"文件上传失败: {file.FileName}", ex);
            restfulResult.Message = i18n.Error_UploadFailed;
        }

        return restfulResult;
    }

    /// <summary>
    /// 内部多文件上传方法
    /// </summary>
    [NonAction]
    private async Task<RestfulResult> UploadMultipleFilesInternal(List<IFormFile> files, string routeCategory)
    {
        RestfulResult restfulResult = new() { Code = CodeStatus.BadRequest };

        if (files == null || files.Count == 0)
        {
            restfulResult.Message = i18n.Prompt_SelectFile;
            return restfulResult;
        }

        var results = new List<UploadResult>();
        var errors = new List<string>();

        foreach (var file in files)
        {
            if (file.Length == 0) continue;

            if (!ValidateFile(file, out var errorMessage))
            {
                errors.Add($"{file.FileName}: {errorMessage}");
                continue;
            }

            try
            {
                var result = await UploadFileAsync(file, routeCategory);
                results.Add(result);
            }
            catch (Exception ex)
            {
                LogFactory.Error($"文件上传失败: {file.FileName}", ex);
                errors.Add($"{file.FileName}: {i18n.Error_UploadFailed}");
            }
        }

        restfulResult.Code = CodeStatus.OK;
        restfulResult.Message = errors.Count > 0 ? i18n.Message_PartialUploadSuccess : i18n.Message_AllUploadSuccess;
        restfulResult.Data = new
        {
            SuccessfulUploads = results,
            FailedUploads = errors
        };

        return restfulResult;
    }

    /// <summary>
    /// 验证文件是否符合配置要求
    /// </summary>
    [NonAction]
    public bool ValidateFile(IFormFile file, out string errorMessage)
    {
        errorMessage = string.Empty;
        var category = GetFileCategory(file);
        var categoryConfig = GetCategoryConfig(category);

        // 使用分类特定配置或全局配置
        var maxFileSize = categoryConfig?.MaxFileSize > 0 ? categoryConfig.MaxFileSize : _uploadConfig.MaxFileSize;
        var allowedExtensions = categoryConfig?.Extensions.Length > 0 ? categoryConfig.Extensions : Array.Empty<string>();
        var allowedMimeTypes = categoryConfig?.MimeTypes.Length > 0 ? categoryConfig.MimeTypes : Array.Empty<string>();
        var maxFileNameLength = categoryConfig?.MaxFileNameLength > 0 ? categoryConfig.MaxFileNameLength : _uploadConfig.MaxFileNameLength;

        // 验证文件大小
        if (file.Length > maxFileSize)
        {
            errorMessage = string.Format(i18n.Error_FileSizeExceeded, maxFileSize / 1024 / 1024);
            return false;
        }

        // 验证文件扩展名
        var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
        if (allowedExtensions.Length > 0 && !allowedExtensions.Contains(fileExtension) && !allowedExtensions.Contains("*"))
        {
            errorMessage = string.Format(i18n.Error_UnsupportedExtension, fileExtension);
            return false;
        }

        // 验证MIME类型
        if (allowedMimeTypes.Length > 0 && !allowedMimeTypes.Contains(file.ContentType) && !allowedMimeTypes.Contains("*"))
        {
            errorMessage = string.Format(i18n.Error_UnsupportedMimeType, file.ContentType);
            return false;
        }

        // 验证文件名长度
        if (file.FileName.Length > maxFileNameLength)
        {
            errorMessage = string.Format(i18n.Error_FileNameTooLong, maxFileNameLength);
            return false;
        }

        return true;
    }

    /// <summary>
    /// 执行文件上传操作
    /// </summary>
    [NonAction]
    public async Task<UploadResult> UploadFileAsync(IFormFile file, string routeCategory)
    {
        var category = GetFileCategory(file);
        var categoryConfig = GetCategoryConfig(category);

        // 获取对应的存储路径
        var storagePath = categoryConfig?.StoragePath ?? _uploadConfig.UploadPath;
        var uploadPath = Path.Combine(_environment.ContentRootPath, storagePath);

        // 创建上传目录（如果不存在）
        if (!Directory.Exists(uploadPath))
        {
            Directory.CreateDirectory(uploadPath);
            LogFactory.Info($"创建存储目录: {uploadPath}");
        }

        // 使用分类特定配置或全局配置
        var useOriginalFileName = categoryConfig?.UseOriginalFileName ?? _uploadConfig.UseOriginalFileName;
        var maxFileNameLength = categoryConfig?.MaxFileNameLength > 0 ? categoryConfig.MaxFileNameLength : _uploadConfig.MaxFileNameLength;
        var overwriteExisting = categoryConfig?.OverwriteExisting ?? _uploadConfig.OverwriteExisting;

        // 生成存储文件名
        string storedFileName;
        if (useOriginalFileName)
        {
            storedFileName = Path.GetFileNameWithoutExtension(file.FileName);
            storedFileName = RemoveInvalidFileNameChars(storedFileName);
            storedFileName = storedFileName.Length > maxFileNameLength
                ? storedFileName.Substring(0, maxFileNameLength)
                : storedFileName;
            storedFileName += Path.GetExtension(file.FileName);
        }
        else
        {
            var fileExtension = Path.GetExtension(file.FileName);
            storedFileName = $"{IdGenerator.Id}{fileExtension}";
        }

        // 处理文件名冲突
        var filePath = Path.Combine(uploadPath, storedFileName);
        if (!overwriteExisting && File.Exists(filePath))
        {
            var fileNameWithoutExt = Path.GetFileNameWithoutExtension(storedFileName);
            var ext = Path.GetExtension(storedFileName);
            var counter = 1;
            while (File.Exists(filePath))
            {
                storedFileName = $"{fileNameWithoutExt}_{counter}{ext}";
                filePath = Path.Combine(uploadPath, storedFileName);
                counter++;
            }
        }

        // 保存文件到指定路径
        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }

        // 返回相对路径，便于前端访问
        var relativePath = Path.GetRelativePath(_environment.ContentRootPath, filePath);
        var normalizedPath = relativePath.Replace("\\", "/");

        return new UploadResult
        {
            FileName = file.FileName,
            StoredFileName = storedFileName,
            FileSize = file.Length,
            FilePath = $"/{normalizedPath}",
            ContentType = file.ContentType,
            UploadTime = DateTime.UtcNow,
            Category = category,
            UploadRoute = routeCategory
        };
    }

    /// <summary>
    /// 获取文件分类信息
    /// </summary>
    [NonAction]
    public string GetFileCategory(IFormFile file)
    {
        var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
        var contentType = file.ContentType.ToLowerInvariant();

        foreach (var mapping in _uploadConfig.FileTypePathMappings)
        {
            // 检查扩展名匹配
            if (mapping.Extensions.Any(ext => ext.Equals(fileExtension, StringComparison.OrdinalIgnoreCase) || ext == "*"))
                return mapping.Category;

            // 检查MIME类型匹配
            if (mapping.MimeTypes.Any(mime => mime.Equals(contentType, StringComparison.OrdinalIgnoreCase) || mime == "*"))
                return mapping.Category;
        }

        return "Unknown";
    }

    /// <summary>
    /// 获取分类配置
    /// </summary>
    [NonAction]
    private FileTypePathMapping GetCategoryConfig(string category)
    {
        return _uploadConfig.FileTypePathMappings
            .FirstOrDefault(m => m.Category.Equals(category, StringComparison.OrdinalIgnoreCase));
    }

    /// <summary>
    /// 移除文件名中的非法字符
    /// </summary>
    [NonAction]
    private string RemoveInvalidFileNameChars(string fileName)
    {
        var invalidChars = Path.GetInvalidFileNameChars();
        return new string(fileName.Where(ch => !invalidChars.Contains(ch)).ToArray());
    }

    #endregion

    #region 辅助接口

    ///// <summary>
    ///// 获取所有可用的上传路由
    ///// </summary>
    ///// <returns>路由信息列表</returns>
    //[HttpGet]
    //public RestfulResult GetUploadRoutes()
    //{
    //    var routes = new List<object>
    //    {
    //        //new { Route = "upload", Description = "通用文件上传", Category = "general" },
    //        new { Route = $"FileUpload/image", Description = "图片文件上传", Category = "Images" },
    //        new { Route = $"FileUpload/document", Description = "文档文件上传", Category = "Documents" },
    //        new { Route = $"FileUpload/spreadsheet", Description = "电子表格上传", Category = "Spreadsheets" },
    //        new { Route = $"FileUpload/presentation", Description = "演示文稿上传", Category = "Presentations" },
    //        new { Route = $"FileUpload/archive", Description = "压缩文件上传", Category = "Archives" },
    //        new { Route = $"FileUpload/code", Description = "代码文件上传", Category = "Code" },
    //        new { Route = $"FileUpload/video", Description = "视频文件上传", Category = "Videos" },
    //        new { Route = $"FileUpload/audio", Description = "音频文件上传", Category = "Audios" },
    //        new { Route = $"FileUpload/ebook", Description = "电子书上传", Category = "Ebooks" },
    //        new { Route = $"FileUpload/other", Description = "其他文件上传", Category = "Others" }
    //    };
    //    return new RestfulResult
    //    {
    //        Code = CodeStatus.OK,
    //        Data = routes
    //    };
    //}

    /// <summary>
    /// 获取文件分类配置信息
    /// </summary>
    /// <returns>分类配置列表</returns>
    [HttpGet]
    public RestfulResult GetFileCategories()
    {
        var categories = _uploadConfig.FileTypePathMappings.Select(m => new
        {
            m.Category,
            m.Extensions,
            m.MimeTypes,
            m.StoragePath,
            m.MaxFileSize,
            m.UseOriginalFileName,
            m.MaxFileNameLength,
            m.OverwriteExisting
        });

        return new RestfulResult
        {
            Code = CodeStatus.OK,
            Data = categories
        };
    }

    #endregion
}